package dao

import (
	"errors"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"web_api_gin/dto"
	"web_api_gin/entity"
)

var SysMenu = SysMenuDao{}

type SysMenuDao struct {
}

//通过菜单分组key获取菜单列表
func (d *SysMenuDao) GetMenuListByKey(ctx *gin.Context, groupKey string) ([]*dto.SysMenusBig, error) {
	groupData, err := SysMenuGroup.GetGroupDataByKey(ctx, groupKey)
	if err != nil {
		return nil, err
	}
	if groupData == nil {
		return nil, errors.New("分组信息不存在")
	}
	menuList, err := d.GetMenuListByGroupId(ctx, groupData.GroupId)
	if err != nil {
		return nil, err
	}

	return menuList, nil
}

//通过分组ID获取菜单列表
func (d *SysMenuDao) GetMenuListByGroupId(ctx *gin.Context, groupId uint32) ([]*dto.SysMenusBig, error) {
	var menuList []*dto.SysMenusBig
	rs := DB(ctx).Table("sys_menus").Select("sys_menus.*,sys_permissions.name as perm_name,sys_permissions.is_public").Joins("left join sys_permissions on sys_menus.perm_id=sys_permissions.perm_id").Where("sys_menus.group_id = ?", groupId).Order("sys_menus.order_num ASC,sys_menus.menu_id ASC").Scan(&menuList)
	return menuList, rs.Error
}

// 通过搜索参数获取菜单列表
func (d *SysMenuDao) GetMenuList(ctx *gin.Context, searchParams *dto.SysMenuGetListRequest) ([]*entity.SysMenu, error) {
	menuList := ([]*entity.SysMenu)(nil)
	tx := DB(ctx).Model(&entity.SysMenu{})
	if searchParams.Name != "" {
		tx = tx.Where("menu_name like ?", "%"+searchParams.Name+"%")
	}
	if searchParams.GroupId != 0 {
		tx = tx.Where("group_id = ?", searchParams.GroupId)
	}
	rs := tx.Order("order_num ASC,menu_id ASC").Find(&menuList)
	return menuList, rs.Error
}

// 获取指定父级ID的下级菜单列表
func (d *SysMenuDao) GetMenuChildList(ctx *gin.Context, ParentId uint32) ([]*entity.SysMenu, error) {
	menuList := ([]*entity.SysMenu)(nil)
	rs := DB(ctx).Model(&entity.SysMenu{}).Where("parent_id = ? ", ParentId).Order("order_num ASC,menu_id ASC").Find(&menuList)
	return menuList, rs.Error
}

// SaveMenu 保存菜单数据
func (d *SysMenuDao) SaveMenu(ctx *gin.Context, data *entity.SysMenu) (int64, error) {
	var rs *gorm.DB
	if data.MenuId != 0 {
		rs = DB(ctx).Select("*").Where("menu_id = ?", data.MenuId).Updates(data)
	} else {
		rs = DB(ctx).Create(data)
	}
	return rs.RowsAffected, rs.Error
}

// 删除菜单
func (d *SysMenuDao) DelMenu(ctx *gin.Context, menuIds []uint32) (int64, error) {
	rs := DB(ctx).Delete(&entity.SysMenu{}, menuIds)
	return rs.RowsAffected, rs.Error
}

// 设置排序
func (d *SysMenuDao) SetOrder(ctx *gin.Context, form *dto.SysMenuSetOrderRequest) error {
	var err error
	switch form.DropType {
	case "before", "after": //拖拽到某个节点之前||拖拽到某个节点之后
		//使用事务闭包
		err = DB(ctx).Transaction(func(tx *gorm.DB) error {
			var newOrderNum uint32
			if form.DropType == "before" { //插到前面取被插队的排序数字作为排序，，后续累加一保持顺序
				newOrderNum = form.DropNode.OrderNum
			} else if form.DropType == "after" { //插到后面取插队排序数字加一作为排序，后续累加一保持顺序
				newOrderNum = form.DropNode.OrderNum + 1
			}
			//事先查出菜单列表
			sameLevelMenuList, err := d.GetMenuChildList(ctx, form.DropNode.ParentId)
			if err != nil {
				return err
			}
			//拖拽节点更改排序数字及父级分类
			tx.Model(&entity.SysMenu{}).Where("menu_id = ? ", form.DraggingNode.MenuId).Updates(entity.SysMenu{ParentId: form.DropNode.ParentId, OrderNum: newOrderNum})
			//调整之后节点的排序数字,之后的节点各加2，为插入节点留空隙
			isStartSet := false
			for _, menu := range sameLevelMenuList {
				if menu.MenuId == form.DropNode.MenuId { //从放置节点开始后续排序自动加一
					isStartSet = true
					if form.DropType == "after" { //插入到后面，则被放置节点不处理
						continue
					}
					if form.DropType == "before" { //插入到前面，从被放置节点开始排序开始调整

					}
				}
				if isStartSet && menu.MenuId != form.DraggingNode.MenuId {
					newOrderNum++
					tx.Model(&entity.SysMenu{}).Where("menu_id = ? ", menu.MenuId).Update("order_num", newOrderNum)
				}
			}
			return nil
		})
	case "inner": //拖进节点，直接更改父级ID
		err = DB(ctx).Model(&entity.SysMenu{}).Where("menu_id = ? ", form.DraggingNode.MenuId).Update("parent_id", form.DropNode.MenuId).Error
	default:
		err = errors.New("无效的节点类型")
	}
	return err
}
